import os
import json
import base64
import hashlib
import uuid
import platform
import pickle
import sys
from datetime import datetime, timedelta
from PyQt5.QtWidgets import (QApplication, QDialog, QVBoxLayout, QLabel,
                             QLineEdit, QPushButton, QMessageBox, QHBoxLayout, QGroupBox)


class TimeDefender:
    """时间防御核心模块"""

    def __init__(self):
        self.record_file = ".td_records"
        self.max_jump = timedelta(hours=2)  # 允许的最大时间跳跃
        self.min_back = timedelta(minutes=5)  # 允许的最小时间回退
        self.first_run = None
        self.last_time = None
        self.load_records()

    def _encrypt(self, data):
        """改进的安全加密方法"""
        if isinstance(data, str):
            data = data.encode('utf-8')  # 将字符串转为字节

        # 确保key是字节类型
        key = b'time_defender_key'  # 固定为字节字符串

        # 处理空数据情况
        if not data:
            return b''

        return bytes([data[i] ^ key[i % len(key)] for i in range(len(data))])

    def load_records(self):
        """加载时间记录"""
        if os.path.exists(self.record_file):
            try:
                with open(self.record_file, 'rb') as f:
                    data = pickle.loads(self._encrypt(f.read()))
                    if isinstance(data, dict):
                        self.first_run = data.get('first')
                        self.last_time = data.get('last')
            except:
                pass

        if not self.first_run:
            self.first_run = datetime.now()
            self.last_time = self.first_run
            self.save_records()

    def save_records(self):
        """保存时间记录"""
        data = {'first': self.first_run, 'last': self.last_time}
        with open(self.record_file, 'wb') as f:
            f.write(self._encrypt(pickle.dumps(data)))

    def validate(self, current=None):
        """验证时间有效性"""
        current = current or datetime.now()

        # 首次运行
        if not self.last_time:
            self.last_time = current
            self.save_records()
            return True

        # 检测时间回退
        if current < self.last_time - self.min_back:
            return False

        # 检测时间跳跃
        if current > self.last_time + self.max_jump:
            return False

        self.last_time = current
        self.save_records()
        return True


class LicenseCore:
    """许可证核心逻辑"""

    def __init__(self, app_name="MyApp"):
        self.app_name = app_name
        self.license_file = "app_license.lic"
        self.td = TimeDefender()
        self.hid = self._get_hardware_id()
        self.license_data = None
        self._load_license()

    def _get_hardware_id(self):
        """生成硬件指纹"""
        components = [
            str(uuid.getnode()),
            platform.processor(),
            platform.machine(),
            str(os.cpu_count())
        ]
        return hashlib.sha256("|".join(components).encode()).hexdigest()

    def _load_license(self):
        """加载许可证"""
        if os.path.exists(self.license_file):
            try:
                with open(self.license_file, 'r') as f:
                    self.license_data = json.load(f)
            except:
                self.license_data = None

    def validate(self):
        """验证许可证"""
        # 时间验证
        if not self.td.validate():
            return False, "系统时间异常"

        # 许可证存在性
        if not self.license_data:
            return False, "未找到许可证"

        # 硬件匹配
        if self.license_data.get("hid") != self.hid:
            return False, "设备不匹配"

        # 有效期检查
        expiry = datetime.strptime(self.license_data["expiry"], "%Y-%m-%d")
        check_time = self.td.last_time or datetime.now()

        if check_time > expiry:
            return False, f"已过期（有效期至 {self.license_data['expiry']}）"

        return True, "许可证有效"

    def register(self, license_code):
        """注册许可证"""
        try:
            # 解码注册码
            data = json.loads(base64.b64decode(license_code).decode())

            # 验证字段
            if not all(k in data for k in ["app", "hid", "expiry"]):
                return False, "无效格式"

            # 硬件验证
            if data["hid"] != self.hid:
                return False, "设备不匹配"

            # 保存许可证
            data["first_act"] = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            with open(self.license_file, 'w') as f:
                json.dump(data, f)

            # 重置时间记录
            self.td = TimeDefender()
            self._load_license()

            return True, "注册成功"
        except Exception as e:
            return False, f"注册失败: {str(e)}"


class LicenseDialog(QDialog):
    def __init__(self, manager):
        super().__init__()
        self.manager = manager
        self.setWindowTitle("无人机照片应用软件注册")
        self.setFixedSize(550, 350)  # 稍微加大窗口

        layout = QVBoxLayout()

        # 设备信息组
        info_group = QGroupBox("设备信息")
        info_layout = QVBoxLayout()

        # 硬件ID显示框 + 复制按钮
        hwid_layout = QHBoxLayout()
        hwid_layout.addWidget(QLabel("硬件ID:"))
        self.hwid_input = QLineEdit(manager.hid)
        self.hwid_input.setReadOnly(True)
        hwid_layout.addWidget(self.hwid_input)

        self.copy_btn = QPushButton("复制")
        self.copy_btn.setToolTip("复制硬件ID到剪贴板")
        self.copy_btn.clicked.connect(self.copy_hardware_id)
        hwid_layout.addWidget(self.copy_btn)

        info_layout.addLayout(hwid_layout)

        # 时间状态显示
        time_status = "✔ 正常" if manager.td.validate() else "✖ 异常"
        time_label = QLabel(f"时间状态: {time_status}")
        info_layout.addWidget(time_label)

        info_group.setLayout(info_layout)
        layout.addWidget(info_group)

        # 注册信息组
        license_group = QGroupBox("注册信息")
        license_layout = QVBoxLayout()
        license_layout.addWidget(QLabel("请输入注册码:"))
        self.code_input = QLineEdit()
        self.code_input.setPlaceholderText("粘贴管理员提供的注册码")
        license_layout.addWidget(self.code_input)
        license_group.setLayout(license_layout)
        layout.addWidget(license_group)

        # 按钮组
        btn_box = QHBoxLayout()
        btn_register = QPushButton("注册")
        btn_register.clicked.connect(self.accept)
        btn_cancel = QPushButton("取消")
        btn_cancel.clicked.connect(self.reject)
        btn_box.addWidget(btn_register)
        btn_box.addWidget(btn_cancel)
        layout.addLayout(btn_box)

        self.setLayout(layout)

    def copy_hardware_id(self):
        """复制硬件ID到剪贴板"""
        clipboard = QApplication.clipboard()
        clipboard.setText(self.manager.hid)
        QMessageBox.information(self, "复制成功", "硬件ID已复制到剪贴板", QMessageBox.Ok)

    def get_code(self):
        return self.code_input.text().strip()

def check_license():
    """主程序调用入口"""
    app = QApplication.instance() or QApplication(sys.argv)
    manager = LicenseCore()

    valid, msg = manager.validate()
    if not valid:
        dialog = LicenseDialog(manager)
        if dialog.exec_() == QDialog.Accepted:
            valid, msg = manager.register(dialog.get_code())
            if not valid:
                QMessageBox.warning(None, "注册失败", msg)
                return False
        else:
            return False

    return valid